package common;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.SortedSet;
import java.util.TreeSet;

import math.LeastSquareMethod;
import math.WLeastSquareMethod;
import math.common.MathCommon;

public class BSTestLSMvsWLSM extends StatTest {

	public BSTestLSMvsWLSM(Double alpha, Map<Double, Double> V_U) {
		super(alpha, V_U);
		// TODO Auto-generated constructor stub
	}
	
	public BSTestLSMvsWLSM() {
		super(0.05);
	}

	@Override
	public Double getStat() {
		ArrayList<Double> V = new ArrayList<Double>(MathCommon.Normalize(V_U).values());
		ArrayList<Double> U = new ArrayList<Double>(MathCommon.Normalize(V_U).keySet());
		Double b11 = new LeastSquareMethod().estimate(V, U);
		Double b12 = new WLeastSquareMethod().estimate(V, U);
		
		int N = V.size();
		int BN = 1000;
		List<Double> BSDiff = new ArrayList<Double> ();
		Double diff = b12 - b11;
		
		Double U2 = 0.0;
		Double U6 = 0.0;
		Double U4 = 0.0;
//		Double b01 = MathCommon.getMean(V_U.values()) - MathCommon.getMean(V_U.keySet())*b11;
		ArrayList<Double> er = new ArrayList<Double>();
		for (int k = 1; k < U.size(); k++) {
			er.add(V.get(k) - b11*U.get(k));
			U2 += Math.pow(U.get(k), 2.0);
			U4 += Math.pow(U.get(k), 4.0);
			U6 += Math.pow(U.get(k), 6.0);
		}
		U2 = 1.0/U2;
		U4 = U6/(U4*U4);
		Double sigma = Math.sqrt(MathCommon.getVar(er)*(U4-U2));
		

		for (int i=0; i<BN; i++) {
			
			ArrayList<Double> V1 = new ArrayList<Double> ();
			ArrayList<Double> U1 = new ArrayList<Double> ();
			for (int j=0; j<N; j++) {
				int k = new Random().nextInt(N);
				V1.add(V.get(k));
				U1.add(U.get(k));
			}
			
			U2 = 0.0;
			U6 = 0.0;
			U4 = 0.0;
//			Double b01 = MathCommon.getMean(V_U.values()) - MathCommon.getMean(V_U.keySet())*b11;
			er = new ArrayList<Double>();
			for (int k = 1; k < U1.size(); k++) {
				er.add(V1.get(k) - b11*U1.get(k));
				U2 += Math.pow(U1.get(k), 2.0);
				U4 += Math.pow(U1.get(k), 4.0);
				U6 += Math.pow(U1.get(k), 6.0);
			}
			U2 = 1.0/U2;
			U4 = U6/(U4*U4);
			Double bsSigma = Math.sqrt(MathCommon.getVar(er)*(U4-U2));
			Double bsDiff = new WLeastSquareMethod().estimate(V1, U1) - new LeastSquareMethod().estimate(V1, U1);
			BSDiff.add(Math.abs(bsDiff - diff)/bsSigma);
			
		}
		Double q = MathCommon.quantile(BSDiff, 1-alpha/2.0);
		if (Math.abs(diff)/sigma <= q)
			return 1.0;
		else return 0.0;
		
//		Collections.sort(BSDiff);
//		Double p;
//		if (BSDiff.get(0) > 0.0) return 0.0;
//		if (BSDiff.get(N-1) < 0.0) return 1.0;
//		int k = 0;
//		for (int i=1; i<BN; i++) {
//			if (BSDiff.get(i) > 0.0) {
//				k = i;
//				break;
//			}
//		}
//		if (k==0) {
//			k = 0;
//		}
//		p = (double)k/BN - ((double)1/BN)*(BSDiff.get(k-1))/(BSDiff.get(k)-BSDiff.get(k-1));
//		return p;
			
		}

	@Override
	public Boolean isH0() {
		// TODO Auto-generated method stub
//		Double stat = getStat();
//		if ((stat < 0.025)||(stat > 0.975))
//			return false;
//		else
//			return true;
		Double stat = getStat();
		if (stat > 0.5)
			return true;
		else
			return false;
	
	}

	@Override
	public Double getQuant() {
		return 3.8415;
	}
	
	public Double getEstDiffH1 () {
		ArrayList<Double> V = new ArrayList<Double>(MathCommon.Normalize(V_U).values());
		ArrayList<Double> U = new ArrayList<Double>(MathCommon.Normalize(V_U).keySet());
		Double b11 = new LeastSquareMethod().estimate(V, U);
		Double b12 = new WLeastSquareMethod().estimate(V, U);
		//return b11-b12;
		return b11;
	}

	@Override
	public Double getQuant(int n) {
		// TODO Auto-generated method stub
		return null;
	}
	

}
